package com.lp.search.service.impl;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lp.feign.UserClients;
import com.lp.model.config.AppResult;
import com.lp.model.config.CodeMsg;
import com.lp.model.constants.ESConstants;
import com.lp.model.dto.search.SearchPageDto;
import com.lp.model.entity.article.vo.PageVO;
import com.lp.model.entity.user.User;
import com.lp.model.exception.ApplicationException;
import com.lp.model.utils.PageUtils;
import com.lp.search.service.IUserSearchService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.SuppressLoggerChecks;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.bootstrap.config.BootstrapPropertySource;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

@Slf4j
@Service
public class UserSearchService implements IUserSearchService {

    @Autowired
    private RestHighLevelClient client;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private UserClients userClients;

    @SneakyThrows
    @Override
    public PageVO<User> search(SearchPageDto pageDto) {
        //1.准备请求
        SearchRequest searchRequest = new SearchRequest(ESConstants.INDEX_USER);
        //2.准备参数
        //1) 搜索数据
        if(!StringUtils.hasLength(pageDto.getContent())) {
            searchRequest.source().query(QueryBuilders.matchAllQuery());
        } else {
            searchRequest.source().query(QueryBuilders.matchQuery(ESConstants.USER_NICKNAME, pageDto.getContent()));
        }
        //2) 分页数据
        int limit = pageDto.getPageSize();
        int offset = (pageDto.getCurPage() - 1) * pageDto.getPageSize();
        searchRequest.source().size(limit).from(offset);
        //3.发送请求，并解析响应
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        PageVO<User> pageVO = handlerResponse(searchResponse);
        return pageVO;
    }

    @SneakyThrows
    @Override
    public void updateByUserId(Long userId) {
        //1.准备请求
        UpdateRequest request = new UpdateRequest(ESConstants.INDEX_USER, userId.toString());
        //2.准备参数
        //1) 远程调用获取用户信息，并解析
        User user = RPCGetUserById(userId);
        //2) 写入参数
        request.doc(objectMapper.writeValueAsString(user), XContentType.JSON);
        //3.发送请求
        client.update(request, RequestOptions.DEFAULT);
    }

    /**
     * 远程调用获取用户信息
     * @param userId  用户 id
     */
    @SneakyThrows
    private User RPCGetUserById(Long userId) {
        //1.远程调用获取用户信息
        String appResultJson = userClients.info(userId);
        //2.解析
        AppResult appResult = objectMapper.readValue(appResultJson, AppResult.class);
        User user = objectMapper.convertValue(appResult.getData(),
                new TypeReference<User>() {});
        if(user == null) {
            log.info(CodeMsg.FAIL_ERROR_RPC_USER.toString());
            throw new ApplicationException(AppResult.fail(CodeMsg.FAIL_ERROR_RPC_USER));
        }
        return user;
    }


    /**
     * 处理搜索响应
     * @param response
     * @return
     */
    @SneakyThrows
    private PageVO<User> handlerResponse(SearchResponse response) {
        //1.解析结果
        SearchHits hits = response.getHits();
        long total = hits.getTotalHits().value;
        SearchHit[] hits1 = hits.getHits();
        List<User> userList = new ArrayList<>();
        for(SearchHit searchHit : hits1) {
            //1) 获取source
            String json = searchHit.getSourceAsString();
            //2) 解析出用户数据
            User user = objectMapper.readValue(json, User.class);
            userList.add(user);
        }
        return PageUtils.getPageVO(userList, total);
    }

}
